import {HttpHeaders, HttpParams} from '@angular/common/http';
import {_HttpClient} from '@delon/theme';
import {Observable, throwError} from 'rxjs';
import {catchError, tap} from 'rxjs/operators';


export const httpOptions = {
  headers: new HttpHeaders({'Content-Type': 'application/json'}),
  withCredentials: true,
};


export abstract class BaseService {
  abstract getUrl(): string;

  protected constructor(public http: _HttpClient) {
  }


  /** GET by id. Will 404 if id not found */
  get(id: number): Observable<any> {
    const url = `${this.getUrl()}/${id}`;
    return this.http.get<any>(url).pipe(
      tap(_ => this.log(`fetched object id=${id}`)),
      catchError(this.handleError<any>(`getany id=${id}`)),
    );
  }

  /** GET by id. Will 404 if id not found */
  getAll(): Observable<any> {
    const url = `${this.getUrl()}/all`;
    return this.http.get<any>(url).pipe(
      tap((obj: any) => this.log(`getAll =${obj}`)),
      catchError(this.handleError<any>(`getAll`)),
    );
  }

  /** GET from the server */
  query(params: HttpParams): Observable<any> {
    return this.http.get(this.getUrl(),
      {
        headers: httpOptions.headers,
        observe: 'response',
        params
      },
    ).pipe(
      tap(() => this.log('query object')),
      catchError(this.handleError('get any', [])),
    );
  }

  queryList(params: string): Observable<any> {
    return this.http.get(this.getUrl() + '/' + params,
    ).pipe(
      tap(() => this.log('query object')),
      catchError(this.handleError('get any', [])),
    );
  }

  findPage(object: any): Observable<any> {
    return this.http.post<any>(this.getUrl() + '/pageList', object, httpOptions).pipe(
      tap((obj: any) => this.log(`added object =${obj}`)),
      catchError(this.handleError<any>('addany')),
    );
  }


  /** POST: add a new object to the server */
  add(object: any): Observable<any> {
    return this.http.post<any>(this.getUrl(), object, httpOptions).pipe(
      tap((obj: any) => this.log(`added object =${obj}`)),
      catchError(this.handleError<any>('addany')),
    );
  }

  /** PUT: update the object on the server */
  update(object: any): Observable<any> {
    return this.http.put<any>(this.getUrl(), object, httpOptions).pipe(
      tap(_ => this.log(`updated object =${object}`)),
      catchError(
        this.handleError<any>('updateany'),
      ),
    );
  }


  /** DELETE: delete the object from the server */
  delete(id: any): Observable<any> {
    const url = `${this.getUrl()}/${id}`;
    return this.http.delete<any>(url, httpOptions).pipe(
      tap(_ => this.log(`deleted object id=${id}`)),
      catchError(this.handleError<any>('deleteany')),
    );
  }


  deleteBatch = (id: any[]): Observable<any> => {
    return this.http.delete<any>(this.getUrl(), {
      'id': id,
    }).pipe(
      tap(_ => this.log(`deleted object list id=${id}`)),
      catchError(this.handleError<any>('delete object list')),
    );
  };

  public handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return throwError(error.error);
    };
  }

  /** Log a HeroService message with the MessageService */
  public log(message: string) {
    console.log(message);
  }


}
